﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EasyTrader.Manager
{
    using OpStateList = List<EasyTrader.Option.StateWatcher>;
    using PriceSignalList = List<EasyTrader.Signal.PriceSignal>;

    public class OptPriceSysManager : SysManager
    {
        // 옵션 주문은 현재 매수만 한다. 다만 상태에 따라 매수 주체만 다르게 바꿀 수 있다.
        public string FindOpOrderCode(int a_StateType)
        {
            string orderCode = "";

            EasyTrader.Option.CompVal firstCallBreakVal = null;
            // 풋의 최신 상태를 가져 온다.
            EasyTrader.Option.CompVal firstPutBreakVal = null;

            //Console.WriteLine("---> SysTime :: " + GlobalVar.DayIndexToTime(m_CurIndex).ToString());
            firstCallBreakVal = m_CallStateWatcher.GetFirstBreakVal("2");
            firstPutBreakVal = m_PutStateWatcher.GetFirstBreakVal("3");
            if (a_StateType == GlobalVar.SignalBuy)
            {
                if (firstCallBreakVal != null)
                {
                    if (firstCallBreakVal.Val > 5.0)
                        m_TotalSigMan.EasyTraderDataSet.DownLoader.GetCallUpDownCode(firstCallBreakVal.BreakCode, 1, out orderCode);
                    else
                        orderCode = firstCallBreakVal.BreakCode;
                }
            }
            else if (a_StateType == GlobalVar.SignalSell)
            {
                if (firstPutBreakVal != null)
                {
                    if (firstPutBreakVal.Val > 5.0)
                        m_TotalSigMan.EasyTraderDataSet.DownLoader.GetPutUpDownCode(firstCallBreakVal.BreakCode, -1, out orderCode);
                    else
                        orderCode = firstPutBreakVal.BreakCode;
                }
            }

            return orderCode;
        }
        private int m_CurIndex = 0;
        public int CurIndex
        {
            get { return m_CurIndex; }
            set { m_CurIndex = value; }
        }
        private EasyTrader.Option.StateWatcherList m_CallStateWatcher = new EasyTrader.Option.StateWatcherList(GlobalVar.OpCallMode);
        public EasyTrader.Option.StateWatcherList CallStateWatcher
        {
            get { return m_CallStateWatcher; }
            set { m_CallStateWatcher = value; }
        }
        private EasyTrader.Option.StateWatcherList m_PutStateWatcher = new EasyTrader.Option.StateWatcherList(GlobalVar.OpPutMode);
        public EasyTrader.Option.StateWatcherList PutStateWatcher
        {
            get { return m_PutStateWatcher; }
            set { m_PutStateWatcher = value; }
        }
        private bool m_StatePrepared = false;

        public void ClearBreakVal()
        {
            m_CallStateWatcher.ClearBreakVal();
            m_PutStateWatcher.ClearBreakVal();
        }

        public void PrepareState()
        {
            if (m_StatePrepared == false && GlobalVar.AllDataDownloaded == true)
            {
                CreateStateList(m_TotalSigMan.EasyTraderDataSet.OptChartTableList);
                FillComVal(Convert.ToInt32(m_TotalSigMan.EasyTraderDataSet.DownLoader.CurDay));
                m_StatePrepared = true;
            }
        }
        // 비교할 값들을 채워 넣는다.
        // 여기에는 월고, 월저, 기준가, 마디가, 목표가가 해당된다.
        private void FillComVal(int a_Date)
        {
            m_CallStateWatcher.Date = a_Date;
            m_PutStateWatcher.Date = a_Date;
            OpStateList stateList = m_CallStateWatcher.StateList;
            for (int i = 0; i < stateList.Count; i++)
            {
                EasyTrader.Option.StateWatcher watcher = stateList[i];
                watcher.ResetDDEInfo(a_Date, m_TotalSigMan);
            }

            stateList = m_PutStateWatcher.StateList;
            for (int i = 0; i < stateList.Count; i++)
            {
                EasyTrader.Option.StateWatcher watcher = stateList[i];
                watcher.ResetDDEInfo(a_Date, m_TotalSigMan);
            }
        }

        // 콜과 풋의 상태 목록을 만들고 초기화 한다.
        // 현재 데이터를 얻어 오는 차트 목록을 기반으로 한다. 
        private void CreateStateList(List<EasyTrader.DataSet.BarDataTable> a_SourceTableList)
        {
            // 일단 모든 상태 목록을 없애 준다.
            m_CallStateWatcher.StateList.Clear();
            m_PutStateWatcher.StateList.Clear();

            for (int i = 0; i < a_SourceTableList.Count; i++)
            {
                EasyTrader.DataSet.BarDataTable table = a_SourceTableList[i];
                string opCode = table.TableName;
                string sideCode = opCode.Substring(0, 1);
                if (sideCode == "2")
                {
                    // 낮은 행사가 먼저 추가되어 높은 값이 나중에 추가됨
                    EasyTrader.Option.StateWatcher stateWatcher = new EasyTrader.Option.StateWatcher();
                    stateWatcher.CreateTypicalValList();
                    stateWatcher.OpCode = opCode;
                    stateWatcher.Table = table;
                    stateWatcher.EasyTraderDataSet = m_TotalSigMan.EasyTraderDataSet;
                    stateWatcher.Parent = m_CallStateWatcher;
                    m_CallStateWatcher.StateList.Add(stateWatcher);
                }
                else if (sideCode == "3")
                {
                    // 낮은 행사가가 먼저 추가되어 높은 행사가가 나중에 추가됨.
                    EasyTrader.Option.StateWatcher stateWatcher = new EasyTrader.Option.StateWatcher();
                    stateWatcher.CreateTypicalValList();
                    stateWatcher.OpCode = opCode;
                    stateWatcher.Table = table;
                    stateWatcher.EasyTraderDataSet = m_TotalSigMan.EasyTraderDataSet;
                    stateWatcher.Parent = m_PutStateWatcher;
                    m_PutStateWatcher.StateList.Add(stateWatcher);
                }
            }
        }


        private void FindCurState()
        {
            //return m_TotalSigMan.FindState(m_SysType, m_FirstSig, m_PriceStateList, m_LogFileName, ref m_CurState);
            // 시스템 상태를 확인한다.
            EasyTrader.Signal.PriceSignal curState = FindSysState();
            // 시스템 상태가 바뀌었을 경우 확인하고 신호정보를 복사하여 추가한다.
            m_TotalSigMan.CheckAddState(m_CurIndex, m_PriceStateList, curState);
        }

        private void SetSigState(ref EasyTrader.Signal.PriceSignal a_Signal, EasyTrader.Option.CompVal a_CallVal, EasyTrader.Option.CompVal a_PutVal)
        {
            if (a_Signal == null)
                return;

            if (a_CallVal != null)
            {
                a_Signal.CallVal = a_CallVal.Val;
                a_Signal.CallType = a_CallVal.Type;
                a_Signal.CallState = a_CallVal.RecentState;
                a_Signal.CallCode = a_CallVal.Watcher.OpCode;
                a_Signal.CallBreakTime = a_CallVal.RecentBreakTime;
            }

            if (a_PutVal != null)
            {
                a_Signal.PutVal = a_PutVal.Val;
                a_Signal.PutType = a_PutVal.Type;
                a_Signal.PutState = a_PutVal.RecentState;
                a_Signal.PutCode = a_PutVal.Watcher.OpCode;
                a_Signal.PutBreakTime = a_PutVal.RecentBreakTime;
            }
        }

        private void SetSigState(ref EasyTrader.Signal.PriceSignal a_Signal, EasyTrader.Option.CompVal a_CallVal, EasyTrader.Option.CompVal a_PutVal, int a_SigType)
        {
            if (a_Signal == null)
                return;

            if (a_CallVal != null)
            {
                a_Signal.CallVal = a_CallVal.Val;
                a_Signal.CallType = a_CallVal.Type;
                a_Signal.CallState = a_CallVal.RecentState;
                a_Signal.CallCode = a_CallVal.Watcher.OpCode;
                a_Signal.CallBreakTime = a_CallVal.RecentBreakTime;
            }

            if (a_PutVal != null)
            {
                a_Signal.PutVal = a_PutVal.Val;
                a_Signal.PutType = a_PutVal.Type;
                a_Signal.PutState = a_PutVal.RecentState;
                a_Signal.PutCode = a_PutVal.Watcher.OpCode;
                a_Signal.PutBreakTime = a_PutVal.RecentBreakTime;
            }

        }

        // 붕괴되는 값들을 모아 놓는다.
        // 만약 붕괴되었던 값이 돌파를 할 경우는 붕괴 목록에서 제외해준다.
        // 따라서 이 목록에는 항상 붕괴된 목록만 존재하게 한다.
        private void CollectPutTargetValues(EasyTrader.Option.CompVal a_BreakVal)
        {
            ;
        }

        // 붕괴되는 값들을 모아 놓는다.
        private void CollectCallTargetValues(EasyTrader.Option.CompVal a_BreakVal)
        {
            ;
        }

        private EasyTrader.Signal.PriceSignal FindSysState()
        {
            EasyTrader.Signal.PriceSignal lastState = m_TotalSigMan.GetLastSignal(m_PriceStateList);

            int stateCount = m_PriceStateList.Count;

            // 콜과 풋의 개별 상태를 갱신해 준다.
            OpStateList stateList = m_CallStateWatcher.StateList;
            for (int i = 0; i < stateList.Count; i++)
            {
                // 낮은 행사가 부터 먼저 조사하고 있음
                EasyTrader.Option.StateWatcher watcher = stateList[i];
                int curDate = Convert.ToInt32(m_TotalSigMan.EasyTraderDataSet.DownLoader.CurDay);
                // 테이블과 dde 값이 일치하지 않으면 일치시켜 준다.
                watcher.CheckTableSync(curDate, m_TotalSigMan);
                // 현재 상태로 갱신해 준다.
                string sideCode = watcher.OpCode.Substring(0, 1);
                if (sideCode == "2")
                    watcher.UpdateSignal(m_CurIndex);
            }

            stateList = m_PutStateWatcher.StateList;
            for (int i = 0; i < stateList.Count; i++)
            {
                // 낮은 행사가 부터 먼저 조사하고 있음
                EasyTrader.Option.StateWatcher watcher = stateList[i];
                int curDate = Convert.ToInt32(m_TotalSigMan.EasyTraderDataSet.DownLoader.CurDay);
                // 테이블과 dde 값이 일치하지 않으면 일치시켜 준다.
                watcher.CheckTableSync(curDate, m_TotalSigMan);
                // 현재 상태로 갱신해 준다.
                string sideCode = watcher.OpCode.Substring(0, 1);
                if (sideCode == "3")
                    watcher.UpdateSignal(m_CurIndex);
            }

            //m_PutStateWatcher.FindBreakDownSignal(m_CurIndex);
            //m_PutStateWatcher.FindBreakUpSignal(m_CurIndex);

            m_CallStateWatcher.CollectBreakUpDownList("2");
            m_PutStateWatcher.CollectBreakUpDownList("3");

            // 콜의 최신 상태를 가져 온다.
            EasyTrader.Option.CompVal firstCallBreakVal = null; 
            // 풋의 최신 상태를 가져 온다.
            EasyTrader.Option.CompVal firstPutBreakVal = null;

            Console.WriteLine("---> SysTime :: " + GlobalVar.DayIndexToTime(m_CurIndex).ToString());
            firstCallBreakVal = m_CallStateWatcher.GetFirstBreakVal("2");
            firstPutBreakVal = m_PutStateWatcher.GetFirstBreakVal("3");
            if (firstCallBreakVal != null)
            {
                Console.WriteLine("firstcallState" + firstCallBreakVal.RecentState.ToString());
                Console.WriteLine("firstcallTime" + firstCallBreakVal.RecentBreakTime.ToString());
                Console.WriteLine("firstcallVal" + firstCallBreakVal.Val.ToString("F2"));
                Console.WriteLine("firstcallCode" + firstCallBreakVal.BreakCode);
                Console.WriteLine("firstcallCurVal" + firstCallBreakVal.CurVal.ToString("F2"));
            }
            if (firstPutBreakVal != null)
            {
                Console.WriteLine("firstputState" + firstPutBreakVal.RecentState.ToString());
                Console.WriteLine("firstputTime" + firstPutBreakVal.RecentBreakTime.ToString());
                Console.WriteLine("firstputVal" + firstPutBreakVal.Val.ToString("F2"));
                Console.WriteLine("firstputCode" + firstPutBreakVal.BreakCode);
                Console.WriteLine("firstputCurVal" + firstPutBreakVal.CurVal.ToString("F2"));
            }
            

            if (firstCallBreakVal == null || firstPutBreakVal == null)
                return null;
            
            if (firstCallBreakVal.RecentState == GlobalVar.BreakUp || firstCallBreakVal.RecentState == GlobalVar.Support)
            {
                // 콜은 돌파 하고 풋은 붕괴한 경우 - 상태를 매수 상태로 바꾼다.
                if (firstPutBreakVal.RecentState == GlobalVar.BreakDown || firstPutBreakVal.RecentState == GlobalVar.Resist)
                {
                    if (firstCallBreakVal.DeltaY > 0.0 && firstPutBreakVal.DeltaY < 0.0)
                    {
                        if (lastState != null && lastState.Type == GlobalVar.SignalBuy)
                            return null;

                        m_TotalSigMan.SetSignalInfo(m_PriceStateList.Count, GlobalVar.SignalBuy, GlobalVar.SignalStateTrans, ref m_CurState);
                        SetSigState(ref m_CurState, firstCallBreakVal, firstPutBreakVal);
                        m_TotalSigMan.WriteStateLog("매수로상태전환", m_LogFileName, m_CurState);
                        m_CallStateWatcher.StartTime = m_CurState.OpTime;
                        m_PutStateWatcher.StartTime = m_CurState.OpTime;
                        return m_CurState;
                    }
                }
            }
            else if (firstCallBreakVal.RecentState == GlobalVar.BreakDown || firstCallBreakVal.RecentState == GlobalVar.Resist)
            {
                // 콜은 붕괴하고 풋은 돌파한 경우 - 상태를 매도 상태로 바꾼다.
                if (firstPutBreakVal.RecentState == GlobalVar.BreakUp || firstPutBreakVal.RecentState == GlobalVar.Support)
                {
                    // 둘다 정확하게 값을 붕괴하거나 돌파했을 때만 진입
                    if (firstCallBreakVal.DeltaY < 0.0 && firstPutBreakVal.DeltaY > 0.0)
                    {
                        if (lastState != null && lastState.Type == GlobalVar.SignalSell)
                            return null;

                        m_TotalSigMan.SetSignalInfo(m_PriceStateList.Count, GlobalVar.SignalSell, GlobalVar.SignalStateTrans, ref m_CurState);
                        SetSigState(ref m_CurState, firstCallBreakVal, firstPutBreakVal);
                        m_TotalSigMan.WriteStateLog("매도로상태전환", m_LogFileName, m_CurState);
                        m_CallStateWatcher.StartTime = m_CurState.OpTime;
                        m_PutStateWatcher.StartTime = m_CurState.OpTime;
                        return m_CurState;
                    }
                }
            }

            if (lastState != null)
            {
                // 풋이 붕괴되고 콜이 돌파된 상태 
                if (lastState.Type == GlobalVar.SignalBuy)
                {
                    firstPutBreakVal = m_PutStateWatcher.FindCompVal(firstPutBreakVal.BreakCode, firstPutBreakVal.Val);
                    // 붕괴된 풋이 붕괴를 벗어나면 청산
                    if (firstPutBreakVal != null && firstPutBreakVal.DeltaY > 0.0)
                    {
                        m_TotalSigMan.SetSignalInfo(m_PriceStateList.Count, GlobalVar.SignalExitBuy, GlobalVar.SignalStateLiquid, ref m_CurState);
                        m_TotalSigMan.WriteSignalLog("매수 청산 신호 발생", m_LogFileName, m_CurState);
                        //m_CurState.BreakDownVal = firstPutBreakVal;
                        SetSigState(ref m_CurState, firstCallBreakVal, firstPutBreakVal);
                        // 모든 상태를 초기화 해준다.
                        ClearState();
                        return m_CurState;
                    }
                }
                else if (lastState.Type == GlobalVar.SignalSell)
                {
                    firstCallBreakVal = m_CallStateWatcher.FindCompVal(firstCallBreakVal.BreakCode, firstCallBreakVal.Val);
                    // 콜이 붕괴되고 풋이 돌파된 상태 
                    if (firstCallBreakVal != null && firstCallBreakVal.DeltaY > 0.0)
                    {
                        m_TotalSigMan.SetSignalInfo(m_PriceStateList.Count, GlobalVar.SignalExitSell, GlobalVar.SignalStateLiquid, ref m_CurState);
                        m_TotalSigMan.WriteSignalLog("매도 청산 신호 발생", m_LogFileName, m_CurState);
                        //m_CurState.BreakDownVal = firstCallBreakVal;
                        SetSigState(ref m_CurState, firstCallBreakVal, firstPutBreakVal);
                        // 모든 상태를 초기화 해준다.
                        ClearState();
                        return m_CurState;
                    }
                }
            }
            return null;
        }

        // 상태를 바탕으로 신호를 발생시킨다.
        private void CheckSignal()
        {
            if (OptPriceSysVar.LastSignalFired == true)
                return;

            EasyTrader.Signal.PriceSignal lastState = m_TotalSigMan.GetLastSignal(m_PriceStateList);
            if (lastState == null)
                return;

            // 먼저 상태 개수를 확인한다.
            // 정해진 상태 개수 안에서만 신호를 발생시킨다.
            int stateCount = m_PriceStateList.Count;
            if (stateCount < OptPriceSysVar.SysStartState ||
                stateCount > OptPriceSysVar.SysEndState)
                return;

            string fCode = m_TotalSigMan.EasyTraderDataSet.DownLoader.GetFutureCode();
            string oCode = FindOpOrderCode(lastState.Type);
            // 먼저 청산을 확인한다.
            // 가격에 의한 청산 신호가 있는지 확인한다.
            EasyTrader.Signal.PriceSignal curSignal = GetLiquidSignalByTotalPrice();
            EasyTrader.Signal.PriceSignal activeSignal = null;
            if (curSignal != null)
            {
                activeSignal = m_TotalSigMan.CheckAddSignal(m_PriceSignalList, curSignal);
                if (OptPriceSysVar.OrderTarget == GlobalVar.OrderTargetFuture)
                {
                    if (fCode != "")
                        SendOrder(activeSignal, fCode, GlobalVar.OrderTargetFuture);
                }
                else
                {
                    if (oCode != "")
                        SendOrder(activeSignal, oCode, GlobalVar.OrderTargetOption);
                }
                OptPriceSysVar.AutoOrder = false;
                OptPriceSysVar.LastSignalFired = true;
                m_TotalSigMan.FireLastSignal(OptPriceSysVar.AutoOrder, GlobalVar.SysTypeOptPrice);
            }
            curSignal = GetLiquidSignalByMaxPrice();
            if (curSignal != null)
            {
                activeSignal = m_TotalSigMan.CheckAddSignal(m_PriceSignalList, curSignal);
                if (OptPriceSysVar.OrderTarget == GlobalVar.OrderTargetFuture)
                {
                    if (fCode != "")
                        SendOrder(activeSignal, fCode, GlobalVar.OrderTargetFuture);
                }
                else
                {
                    if (oCode != "")
                        SendOrder(activeSignal, oCode, GlobalVar.OrderTargetOption);
                }
                OptPriceSysVar.AutoOrder = false;
                OptPriceSysVar.LastSignalFired = true;
                m_TotalSigMan.FireLastSignal(OptPriceSysVar.AutoOrder, GlobalVar.SysTypeJisuWaveHogaSummit);
            }

            curSignal = GetLiquidSignalByTotalPriceStepByStep();
            if (curSignal != null)
            {
                activeSignal = m_TotalSigMan.CheckAddSignal(m_PriceSignalList, curSignal);
                //SendLiquidOrder(activeSignal);
                if (OptPriceSysVar.OrderTarget == GlobalVar.OrderTargetFuture)
                {
                    if (fCode != "")
                        SendOrder(activeSignal, fCode, GlobalVar.OrderTargetFuture);
                }
                else
                {
                    if (oCode != "")
                        SendOrder(activeSignal, oCode, GlobalVar.OrderTargetOption);
                }
                // 단계별 총 청산액을 증가시켜 준다.
                OptPriceSysVar.TotalProfitStepLiquidVal += OptPriceSysVar.StepLiquidVal;
            }

            curSignal = GetLiquidSignalByStateCountStepByStep();
            if (curSignal != null)
            {
                activeSignal = m_TotalSigMan.CheckAddSignal(m_PriceSignalList, curSignal);
                //SendLiquidOrder(activeSignal);
                if (OptPriceSysVar.OrderTarget == GlobalVar.OrderTargetFuture)
                {
                    if (fCode != "")
                        SendOrder(activeSignal, fCode, GlobalVar.OrderTargetFuture);
                }
                else
                {
                    if (oCode != "")
                        SendOrder(activeSignal, oCode, GlobalVar.OrderTargetOption);
                }
                // 단계별 상태값을 증가시켜 준다.
                OptPriceSysVar.StepLiquidStateCount++;
            }
            curSignal = GetLiquidSignalByPerPrice();
            if (curSignal != null)
            {
                activeSignal = m_TotalSigMan.CheckAddSignal(m_PriceSignalList, curSignal);
                if (OptPriceSysVar.OrderTarget == GlobalVar.OrderTargetFuture)
                {
                    if (fCode != "")
                        SendOrder(activeSignal, fCode, GlobalVar.OrderTargetFuture);
                }
                else
                {
                    if (oCode != "")
                        SendOrder(activeSignal, oCode, GlobalVar.OrderTargetOption);
                }
            }
            // 시간에 의한 청산 신호가 있는지 확인한다.
            curSignal = GetLiquidSignalByTime();
            if (curSignal != null)
            {
                activeSignal = m_TotalSigMan.CheckAddSignal(m_PriceSignalList, curSignal);
                //SendOrder(activeSignal);
                if (OptPriceSysVar.OrderTarget == GlobalVar.OrderTargetFuture)
                {
                    if (fCode != "")
                        SendOrder(activeSignal, fCode, GlobalVar.OrderTargetFuture);
                }
                else
                {
                    if (oCode != "")
                        SendOrder(activeSignal, oCode, GlobalVar.OrderTargetOption);
                }
                OptPriceSysVar.AutoOrder = false;
                OptPriceSysVar.LastSignalFired = true;
                m_TotalSigMan.FireLastSignal(OptPriceSysVar.AutoOrder, GlobalVar.SysTypeOptPrice);
            }
            // 상태 개수에 의한 청산 신호가 있는지 확인한다.
            curSignal = GetLiquidSignalByStateCount();
            if (curSignal != null)
            {
                activeSignal = m_TotalSigMan.CheckAddSignal(m_PriceSignalList, curSignal);
                if (OptPriceSysVar.OrderTarget == GlobalVar.OrderTargetFuture)
                {
                    if (fCode != "")
                        SendOrder(activeSignal, fCode, GlobalVar.OrderTargetFuture);
                }
                else
                {
                    if (oCode != "")
                        SendOrder(activeSignal, oCode, GlobalVar.OrderTargetOption);
                }
                OptPriceSysVar.AutoOrder = false;
                OptPriceSysVar.LastSignalFired = true;
                m_TotalSigMan.FireLastSignal(OptPriceSysVar.AutoOrder, GlobalVar.SysTypeOptPrice);
            }
            // 붕괴 목록에 의한 신호가 있는지 확인한다.
            curSignal = GetSignalByBreakDownList();
            if (curSignal != null)
            {
                activeSignal = CheckAddSignal(m_PriceSignalList, curSignal);
                if (OptPriceSysVar.OrderTarget == GlobalVar.OrderTargetFuture)
                {
                    if (fCode != "")
                        SendOrder(activeSignal, fCode, GlobalVar.OrderTargetFuture);
                }
                else
                {
                    if (oCode != "")
                        SendOrder(activeSignal, oCode, GlobalVar.OrderTargetOption);
                }
            }
        }


        private EasyTrader.Signal.PriceSignal FindSameLiqDownSignal(string a_OpCode, double a_Val, int a_SigType)
        {
            int count = m_PriceSignalList.Count;
            if (count == 0)
                return null;

            for (int i = count - 1; i >= 0; i--)
            {
                EasyTrader.Signal.PriceSignal curSignal = m_PriceSignalList[i];
                if (curSignal.Type != a_SigType)
                {
                    return null;
                }

                if (curSignal.Type == a_SigType)
                {
                    if (curSignal.OptSigCode == a_OpCode && curSignal.OptSigVal == a_Val)
                        return curSignal;
                }
            }

            return null;
        }

        public EasyTrader.Signal.PriceSignal CheckAddSignal(PriceSignalList a_SignalList, EasyTrader.Signal.PriceSignal a_Signal)
        {
            if (a_Signal == null || a_SignalList == null)
                return null;
            int count = a_SignalList.Count;

            EasyTrader.Signal.PriceSignal newSignal = null;
            if (count <= 0)
            {
                newSignal = a_Signal.Clone();
                a_SignalList.Add(newSignal);
                return newSignal;
            }
            else
            {
                // 선물 본 신호로 필터링
                EasyTrader.Signal.PriceSignal prevSignal = a_SignalList[count - 1];
                if (prevSignal.Type == GlobalVar.SignalExitBuy || prevSignal.Type == GlobalVar.SignalExitSell)
                {
                    if (a_Signal.Type == GlobalVar.SignalExitBuy || 
                        a_Signal.Type == GlobalVar.SignalExitSell ||
                        a_Signal.Type == GlobalVar.SignalSellPartialLiquid ||
                        a_Signal.Type == GlobalVar.SignalBuyPartialLiquid)
                    {
                        return null;
                    }
                }

                if (prevSignal.OptSigCode != a_Signal.OptSigCode)
                {
                    if (a_Signal.Type == GlobalVar.SignalSellPartialLiquid ||
                    a_Signal.Type == GlobalVar.SignalBuyPartialLiquid)
                    {
                        EasyTrader.Signal.PriceSignal sameSignal = FindSameLiqDownSignal(a_Signal.OptSigCode, a_Signal.OptSigVal, a_Signal.Type);
                        if (sameSignal == null)
                        {
                            newSignal = a_Signal.Clone();
                            a_SignalList.Add(newSignal);
                            return newSignal;
                        }
                    }
                    else
                    {
                        newSignal = a_Signal.Clone();
                        a_SignalList.Add(newSignal);
                        return newSignal;
                    }
                }
                else
                {
                    if (prevSignal.OptSigType != a_Signal.OptSigType)
                    {
                        newSignal = a_Signal.Clone();
                        a_SignalList.Add(newSignal);
                        return newSignal;
                    }
                    else
                    {
                        if (prevSignal.OptSigVal != a_Signal.OptSigVal)
                        {
                            newSignal = a_Signal.Clone();
                            a_SignalList.Add(newSignal);
                            return newSignal;
                        }
                    }
                }
            }

            return null;
        }

        private EasyTrader.Signal.PriceSignal GetSignalByBreakDownList()
        {
            EasyTrader.Signal.PriceSignal lastSignal = m_TotalSigMan.GetLastSignal(m_PriceSignalList);
            EasyTrader.Signal.PriceSignal lastState = m_TotalSigMan.GetLastSignal(m_PriceStateList);
            EasyTrader.Signal.PriceSignal prevState = m_TotalSigMan.GetPrevSignal(m_PriceStateList);
            if (lastState == null)
                return null;

            m_CallStateWatcher.FindBreakDownSignal(m_CurIndex);
            m_PutStateWatcher.FindBreakDownSignal(m_CurIndex);

            /*
            if (callBreakDownSignal != null)
            {
                Console.WriteLine("callBreakDown=>OptSigTime : " + callBreakDownSignal.OptSigTime.ToString());
                Console.WriteLine("callBreakDown=>OptSigType : " + callBreakDownSignal.OptSigType.ToString());
                Console.WriteLine("callBreakDown=>OptSigVal : " + callBreakDownSignal.OptSigVal.ToString("F2"));
                Console.WriteLine("callBreakDown=>OptSigCode : " + callBreakDownSignal.OptSigCode);
            }

            if (putBreakDownSignal != null)
            {
                Console.WriteLine("putBreakDown=>OptSigTime : " + putBreakDownSignal.OptSigTime.ToString());
                Console.WriteLine("putBreakDown=>OptSigType : " + putBreakDownSignal.OptSigType.ToString());
                Console.WriteLine("putBreakDown=>OptSigVal : " + putBreakDownSignal.OptSigVal.ToString("F2"));
                Console.WriteLine("putBreakDown=>OptSigCode : " + putBreakDownSignal.OptSigCode);
            }
            */
            if (lastState.Type == GlobalVar.SignalExitBuy)
            {
                EasyTrader.Signal.PriceSignal putBreakDownSignal = m_PutStateWatcher.GetRecentBreakDownSignal();

                m_TotalSigMan.SetSignalInfo(m_CurIndex, m_PriceStateList.Count, GlobalVar.SignalExitBuy, GlobalVar.SignalStateLiquid, ref m_CurState);

                if (putBreakDownSignal != null)
                {
                    m_CurState.OptSigTime = putBreakDownSignal.OptSigTime;
                    m_CurState.OptSigCode = putBreakDownSignal.OptSigCode;
                    m_CurState.OptSigType = putBreakDownSignal.OptSigType;
                    m_CurState.OptSigVal = putBreakDownSignal.OptSigVal;
                }


                m_TotalSigMan.WriteSignalLog("매수 청산 신호 발생", m_LogFileName, m_CurState);
                m_PutStateWatcher.ClearOptValList();
                m_CallStateWatcher.ClearOptValList();
                return m_CurState;
            }
            else if (lastState.Type == GlobalVar.SignalExitSell)
            {
                EasyTrader.Signal.PriceSignal callBreakDownSignal = m_CallStateWatcher.GetRecentBreakDownSignal();

                m_TotalSigMan.SetSignalInfo(m_CurIndex, m_PriceStateList.Count, GlobalVar.SignalExitSell, GlobalVar.SignalStateLiquid, ref m_CurState);

                if (callBreakDownSignal != null)
                {
                    m_CurState.OptSigTime = callBreakDownSignal.OptSigTime;
                    m_CurState.OptSigCode = callBreakDownSignal.OptSigCode;
                    m_CurState.OptSigType = callBreakDownSignal.OptSigType;
                    m_CurState.OptSigVal = callBreakDownSignal.OptSigVal;
                }


                m_TotalSigMan.WriteSignalLog("매도 청산 신호 발생", m_LogFileName, m_CurState);
                m_PutStateWatcher.ClearOptValList();
                m_CallStateWatcher.ClearOptValList();
                return m_CurState;
            }
            // 매도 상태에서는 콜이 붕괴된 목록을 가지고 신호를 제어한다.
            else if (lastState.Type == GlobalVar.SignalSell)
            {
                EasyTrader.Signal.PriceSignal callBreakDownSignal = m_CallStateWatcher.GetRecentBreakDownSignal();

                if (callBreakDownSignal != null)
                {
                    Console.WriteLine("callBreakDown=>OptSigTime : " + callBreakDownSignal.OptSigTime.ToString());
                    Console.WriteLine("callBreakDown=>OptSigType : " + callBreakDownSignal.OptSigType.ToString());
                    Console.WriteLine("callBreakDown=>OptSigVal : " + callBreakDownSignal.OptSigVal.ToString("F2"));
                    Console.WriteLine("callBreakDown=>OptSigCode : " + callBreakDownSignal.OptSigCode);
                }
                if (m_CallStateWatcher.GetOptValCount() >= 2)
                {
                    EasyTrader.Option.OptValItem optItem = m_CallStateWatcher.GetPrevOptValItem();
                    if (optItem != null)
                    {
                        EasyTrader.Option.CompVal prevLiq = m_CallStateWatcher.FindCompVal(optItem.Code, optItem.Val);
                        if (prevLiq != null)
                        {
                            if (prevLiq.DeltaY > 0)
                            {
                                m_TotalSigMan.SetSignalInfo(m_CurIndex, m_PriceStateList.Count, GlobalVar.SignalExitSell, GlobalVar.SignalStateLiquid, ref m_CurState);

                                if (callBreakDownSignal != null)
                                {
                                    m_CurState.OptSigTime = callBreakDownSignal.OptSigTime;
                                    m_CurState.OptSigCode = callBreakDownSignal.OptSigCode;
                                    m_CurState.OptSigType = callBreakDownSignal.OptSigType;
                                    m_CurState.OptSigVal = callBreakDownSignal.OptSigVal;
                                }


                                m_TotalSigMan.WriteSignalLog("매도 청산 신호 발생", m_LogFileName, m_CurState);
                                m_PutStateWatcher.ClearOptValList();
                                m_CallStateWatcher.ClearOptValList();
                                return m_CurState;
                            }
                        }
                    }
                }
                if (lastSignal == null)
                {
                    m_TotalSigMan.SetSignalInfo(m_CurIndex, m_PriceStateList.Count, GlobalVar.SignalSell, GlobalVar.SignalStateTrans, ref m_CurState);
                    if (callBreakDownSignal != null)
                    {
                        m_CurState.OptSigTime = callBreakDownSignal.OptSigTime;
                        m_CurState.OptSigCode = callBreakDownSignal.OptSigCode;
                        m_CurState.OptSigType = callBreakDownSignal.OptSigType;
                        m_CurState.OptSigVal = callBreakDownSignal.OptSigVal;
                    }

                    m_TotalSigMan.WriteSignalLog("최초매도 전환 신호 발생", m_LogFileName, m_CurState);
                    return m_CurState;
                }
                else
                {
                    if (prevState != null)
                    {
                        // 이전 상태가 청산 상태였거나 이전 상태가 매수 상태 였을 때 - 이전 신호가 청산 신호 였다면 신규 진입이 된다.
                        if (prevState.Type == GlobalVar.SignalExitBuy || prevState.Type == GlobalVar.SignalExitSell || prevState.Type == GlobalVar.SignalBuy)
                        {
                            if (lastSignal == null)
                            {
                                m_TotalSigMan.SetSignalInfo(m_CurIndex, m_PriceStateList.Count, GlobalVar.SignalSell, GlobalVar.SignalStateTrans, ref m_CurState);

                                if (callBreakDownSignal != null)
                                {
                                    m_CurState.OptSigTime = callBreakDownSignal.OptSigTime;
                                    m_CurState.OptSigCode = callBreakDownSignal.OptSigCode;
                                    m_CurState.OptSigType = callBreakDownSignal.OptSigType;
                                    m_CurState.OptSigVal = callBreakDownSignal.OptSigVal;
                                }

                                m_TotalSigMan.WriteSignalLog("매도 전환 신호 발생", m_LogFileName, m_CurState);
                                return m_CurState;
                            }
                            else
                            {
                                if (lastSignal.Type != GlobalVar.SignalSell && lastSignal.Type != GlobalVar.SignalSellPartialLiquid && lastSignal.Type != GlobalVar.SignalExitSell)
                                {
                                    m_TotalSigMan.SetSignalInfo(m_CurIndex, m_PriceStateList.Count, GlobalVar.SignalSell, GlobalVar.SignalStateTrans, ref m_CurState);

                                    if (callBreakDownSignal != null)
                                    {
                                        m_CurState.OptSigTime = callBreakDownSignal.OptSigTime;
                                        m_CurState.OptSigCode = callBreakDownSignal.OptSigCode;
                                        m_CurState.OptSigType = callBreakDownSignal.OptSigType;
                                        m_CurState.OptSigVal = callBreakDownSignal.OptSigVal;
                                    }

                                    m_TotalSigMan.WriteSignalLog("매도 전환 신호 발생", m_LogFileName, m_CurState);
                                    return m_CurState;
                                }
                            }
                        }
                    }

                    if (callBreakDownSignal != null)
                    {
                        if (callBreakDownSignal.OptSigType == GlobalVar.OpSignalDownLiq) // 익절
                        //if (callBreakDownSignal.OptSigType == GlobalVar.OpSignalSupport) // 익
                        {
                            m_CallStateWatcher.AddOptVal(callBreakDownSignal.OptSigCode, callBreakDownSignal.OptSigVal);
                            // 매도 일부 청산 신호 발생
                            m_TotalSigMan.SetSignalInfo(m_CurIndex, m_PriceStateList.Count, GlobalVar.SignalSellPartialLiquid, GlobalVar.SignalStateLiquid, ref m_CurState);
                            if (callBreakDownSignal != null)
                            {
                                m_CurState.OptSigTime = callBreakDownSignal.OptSigTime;
                                m_CurState.OptSigCode = callBreakDownSignal.OptSigCode;
                                m_CurState.OptSigType = callBreakDownSignal.OptSigType;
                                m_CurState.OptSigVal = callBreakDownSignal.OptSigVal;
                            }

                            m_TotalSigMan.WriteSignalLog("매도 일부 청산 신호 발생", m_LogFileName, m_CurState);
                            return m_CurState;
                        }
                    }
                }
            }
            else if (lastState.Type == GlobalVar.SignalBuy) // 매수 상태에서는 풋이 붕괴된 목록을 가지고 신호를 제어한다.
            {
                EasyTrader.Signal.PriceSignal putBreakDownSignal = m_PutStateWatcher.GetRecentBreakDownSignal();

                if (m_PutStateWatcher.GetOptValCount() >= 2)
                {
                    EasyTrader.Option.OptValItem optItem = m_PutStateWatcher.GetPrevOptValItem();
                    if (optItem != null)
                    {
                        EasyTrader.Option.CompVal prevLiq = m_PutStateWatcher.FindCompVal(optItem.Code, optItem.Val);
                        if (prevLiq != null)
                        {
                            if (prevLiq.DeltaY > 0)
                            {
                                m_TotalSigMan.SetSignalInfo(m_CurIndex, m_PriceStateList.Count, GlobalVar.SignalExitBuy, GlobalVar.SignalStateLiquid, ref m_CurState);

                                if (putBreakDownSignal != null)
                                {
                                    m_CurState.OptSigTime = putBreakDownSignal.OptSigTime;
                                    m_CurState.OptSigCode = putBreakDownSignal.OptSigCode;
                                    m_CurState.OptSigType = putBreakDownSignal.OptSigType;
                                    m_CurState.OptSigVal = putBreakDownSignal.OptSigVal;
                                }


                                m_TotalSigMan.WriteSignalLog("매수 청산 신호 발생", m_LogFileName, m_CurState);

                                m_PutStateWatcher.ClearOptValList();
                                m_CallStateWatcher.ClearOptValList();
                                return m_CurState;
                            }
                        }
                    }
                }
                if (lastSignal == null)
                {
                    m_TotalSigMan.SetSignalInfo(m_CurIndex, m_PriceStateList.Count, GlobalVar.SignalBuy, GlobalVar.SignalStateTrans, ref m_CurState);

                    if (putBreakDownSignal != null)
                    {
                        m_CurState.OptSigTime = putBreakDownSignal.OptSigTime;
                        m_CurState.OptSigCode = putBreakDownSignal.OptSigCode;
                        m_CurState.OptSigType = putBreakDownSignal.OptSigType;
                        m_CurState.OptSigVal = putBreakDownSignal.OptSigVal;
                    }

                    m_TotalSigMan.WriteSignalLog("최초매수 전환 신호 발생", m_LogFileName, m_CurState);
                    return m_CurState;
                }
                else
                {
                    if (prevState != null)
                    {
                        // 이전 상태가 청산 상태였거나 이전 상태가 매수 상태 였을 때 - 이전 신호가 청산 신호 였다면 신규 진입이 된다.
                        if (prevState.Type == GlobalVar.SignalExitBuy || prevState.Type == GlobalVar.SignalExitSell || prevState.Type == GlobalVar.SignalSell)
                        {

                            if (lastSignal == null)
                            {
                                m_TotalSigMan.SetSignalInfo(m_CurIndex, m_PriceStateList.Count, GlobalVar.SignalBuy, GlobalVar.SignalStateTrans, ref m_CurState);
                                if (putBreakDownSignal != null)
                                {
                                    m_CurState.OptSigTime = putBreakDownSignal.OptSigTime;
                                    m_CurState.OptSigCode = putBreakDownSignal.OptSigCode;
                                    m_CurState.OptSigType = putBreakDownSignal.OptSigType;
                                    m_CurState.OptSigVal = putBreakDownSignal.OptSigVal;
                                }

                                m_TotalSigMan.WriteSignalLog("매수 전환 신호 발생", m_LogFileName, m_CurState);
                                return m_CurState;
                            }
                            else
                            {
                                if (lastSignal.Type != GlobalVar.SignalBuy && lastSignal.Type != GlobalVar.SignalBuyPartialLiquid && lastSignal.Type != GlobalVar.SignalExitBuy)
                                {
                                    m_TotalSigMan.SetSignalInfo(m_CurIndex, m_PriceStateList.Count, GlobalVar.SignalBuy, GlobalVar.SignalStateTrans, ref m_CurState);
                                    if (putBreakDownSignal != null)
                                    {
                                        m_CurState.OptSigTime = putBreakDownSignal.OptSigTime;
                                        m_CurState.OptSigCode = putBreakDownSignal.OptSigCode;
                                        m_CurState.OptSigType = putBreakDownSignal.OptSigType;
                                        m_CurState.OptSigVal = putBreakDownSignal.OptSigVal;
                                    }

                                    m_TotalSigMan.WriteSignalLog("매수 전환 신호 발생", m_LogFileName, m_CurState);
                                    return m_CurState;
                                }
                            }
                        }
                    }

                    if (putBreakDownSignal != null)
                    {
                        if (putBreakDownSignal.OptSigType == GlobalVar.OpSignalDownLiq) // 익절
                        //if (putBreakDownSignal.OptSigType == GlobalVar.OpSignalSupport)
                        {
                            m_PutStateWatcher.AddOptVal(putBreakDownSignal.OptSigCode, putBreakDownSignal.OptSigVal);

                            m_TotalSigMan.SetSignalInfo(m_CurIndex, m_PriceStateList.Count, GlobalVar.SignalBuyPartialLiquid, GlobalVar.SignalStateLiquid, ref m_CurState);
                            if (putBreakDownSignal != null)
                            {
                                m_CurState.OptSigTime = putBreakDownSignal.OptSigTime;
                                m_CurState.OptSigCode = putBreakDownSignal.OptSigCode;
                                m_CurState.OptSigType = putBreakDownSignal.OptSigType;
                                m_CurState.OptSigVal = putBreakDownSignal.OptSigVal;
                            }

                            m_TotalSigMan.WriteSignalLog("매수 일부 청산 신호 발생", m_LogFileName, m_CurState);
                            return m_CurState;
                        }
                    }
                }
            }

            return null;
        }

        public void ClearState()
        {
            OpStateList stateList = m_CallStateWatcher.StateList;
            for (int i = 0; i < stateList.Count; i++)
            {
                EasyTrader.Option.StateWatcher watcher = stateList[i];
                // 먼저 상태를 초기화 한다.
                watcher.ClearState();
            }

            m_CallStateWatcher.ClearBreakVal();

            stateList = m_PutStateWatcher.StateList;
            for (int i = 0; i < stateList.Count; i++)
            {
                EasyTrader.Option.StateWatcher watcher = stateList[i];
                // 먼저 상태를 초기화 한다.
                watcher.ClearState();
            }

            m_PutStateWatcher.ClearBreakVal();
        }


        // 단계별로 청산 값을 적용해 본다.
        protected EasyTrader.Signal.PriceSignal GetLiquidSignalByStep()
        {
            EasyTrader.Signal.PriceSignal lastSignal = m_TotalSigMan.GetLastSignal(m_PriceSignalList);
            // 가장 최근의 상태를 가져 온다. 이 상태를 바탕으로 새로운 신호를 만들어 낸다.
            EasyTrader.Signal.PriceSignal lastState = m_TotalSigMan.GetLastSignal(m_PriceStateList);
            if (lastState == null)
                return null;
            // 현재 상태 번호를 구한다.
            int curStateNumber = m_PriceStateList.Count;
            if (lastSignal != null)
            {
                // 이전 신호와 현재 신호 타입이 같을 때는 아무일도 하지 않는다.
                if (lastSignal.Type == lastState.Type)
                    return null;
            }

            int signalVal = GlobalVar.SignalNone;
            if (lastState.Type == GlobalVar.SignalBuy)
            {
                /*
                signalVal = GlobalVar.SignalBuy;
                m_TotalSigMan.SetSignalInfo(m_PriceStateList.Count, signalVal, GlobalVar.SignalStateTrans, ref m_CurState);
                m_TotalSigMan.WriteSignalLog("매수 전환 신호 발생", m_LogFileName, m_CurState);
                 */
                for (int i = 0; i < m_CallStateWatcher.UpTargetList.Count; i++)
                {
                    EasyTrader.Option.CompVal curCompVal = m_CallStateWatcher.UpTargetList[i];
                    // 비교할 값이 0일 때는 아무일도 하지 않는다.
                    if (curCompVal.Val == 0.0)
                        continue;

                    double outClose = 0.0;
                    int sameValCount = curCompVal.Watcher.GetHighLowSameValueCount(m_CurIndex, 10, 1, out outClose);
                    // 목표값과 현재값의 차이를 구한다.
                    double deltaTarget = outClose - curCompVal.Val;
                    if (outClose == curCompVal.Val)
                    {
                        if (deltaTarget > 0)
                        {
                            if (sameValCount < 3) // 동일한 값이 2개 이하 일때
                            {
                                // 동일한 값이 2개 이하인데 이미 목표값을 넘었을 경우에는 시간상으로 넘은 시간이 3분 경과한 후에 청산을 내보낸다. 
                                int timeGap = m_CurIndex - curCompVal.Watcher.BreakUpIndex;
                                if (timeGap >= 3)
                                {
                                    // 같은 상태에서 청산이 여러번 일어 날 수 있기 때문에 이 부분은 단계별 청산을 만들어 다시 적용해야 한다.
                                    m_TotalSigMan.SetSignalInfo(m_PriceStateList.Count, GlobalVar.SignalExitBuy, GlobalVar.SignalStateLiquid, ref m_CurState);
                                    m_TotalSigMan.WriteSignalLog("단계별 목표 도달에 의한 청산신호 발생", m_LogFileName, m_CurState);
                                    return m_CurState;
                                }
                            }
                        }
                        else
                        {
                            if (sameValCount >= 3) // 동일한 값이 3개 이상일 때
                            {
                                // 동일한 값이 3개 이상일 때는 목표값에서 확실한 저항이 있는 것으로 보고 바로 청산을 내보낸다.
                                // 같은 상태에서 청산이 여러번 일어 날 수 있기 때문에 이 부분은 단계별 청산을 만들어 다시 적용해야 한다.
                                m_TotalSigMan.SetSignalInfo(m_PriceStateList.Count, GlobalVar.SignalExitBuy, GlobalVar.SignalStateLiquid, ref m_CurState);
                                m_TotalSigMan.WriteSignalLog("단계별 목표 도달에 의한 청산신호 발생", m_LogFileName, m_CurState);
                                return m_CurState;
                            }
                        }
                    }
                }
                return m_CurState;
            }
            else if (lastState.Type == GlobalVar.SignalSell)
            {
                /*
                signalVal = GlobalVar.SignalSell;
                m_TotalSigMan.SetSignalInfo(m_PriceStateList.Count, signalVal, GlobalVar.SignalStateTrans, ref m_CurState);
                m_TotalSigMan.WriteSignalLog("매도 전환 신호 발생", m_LogFileName, m_CurState);
                 */
                for (int i = 0; i < m_PutStateWatcher.UpTargetList.Count; i++)
                {
                    EasyTrader.Option.CompVal curCompVal = m_PutStateWatcher.UpTargetList[i];
                    double outClose = 0.0;
                    int sameValCount = curCompVal.Watcher.GetHighLowSameValueCount(m_CurIndex, 10, 1, out outClose);
                    // 목표값과 현재값의 차이를 구한다.
                    double deltaTarget = outClose - curCompVal.Val;
                    if (sameValCount < 2) // 동일한 값이 1개 이하 일때
                    {
                        ;
                    }
                    else if (sameValCount < 3) // 동일한 값이 2개 이하 일 때
                    {
                        ;
                    }
                    else // 동일한 값이 3개 이상일 때
                    {
                        ;
                    }
                }
                return m_CurState;
            }
            
            return null;
        }


        public void UpdateSysState()
        {
            m_CurIndex = m_TotalSigMan.CurIndex;
            Console.WriteLine("OptSysIndex = " + m_CurIndex.ToString());
            // 옵션 가격을 일단 다 받고 등가가 확정된 뒤에 신호를 발생해 준다.
            if (m_TotalSigMan.EasyTraderDataSet.DownLoader.AllOptChartDataDownloaded == true &&
                m_TotalSigMan.EasyTraderDataSet.DownLoader.ATMChanged == true)
            {
                FindCurState();
                CheckSignal();
            }
        }
    }
}
